package practice;

import practice.common.DException;
import practice.common.Number;
import practice.common.TimeZone;

import java.lang.reflect.Field;
import java.math.BigDecimal;
import java.time.Duration;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.zone.ZoneRules;

public class CallTip2 {
    private final LocalDateTime responseTime;
    private final LocalDateTime endTime;
    private final String zone;
    private final boolean isInOverLap;

    /**
     *
     * @param responseTime
     * @param endTime
     * @param zone
     * @throws DException
     */
    public CallTip2(final LocalDateTime responseTime, final LocalDateTime endTime,
                    final boolean isInOverLap, final String zone) {
        this.responseTime = responseTime;
        this.endTime = endTime;
        this.zone = zone;
        this.isInOverLap = isInOverLap;
    }

    /**
     * 判断时区是否实行夏令时
     * 部分有夏令时时区已放入TimeZone类中
     * @return
     * true 有夏令时
     * false 无夏令时
     */
    public boolean haveDaylightSavings() {
        for (Field field : TimeZone.class.getDeclaredFields()) {
            try {
                if (field.get(this).equals(zone)) {
                    return true;
                }
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            }
        }
        return false;
    }

    /**
     * 计算两个时间之间的秒数
     * @return
     */
    public long calculateTimeSpan() {
        Duration duration = Duration.between(responseTime, endTime);
        long seconds = Math.abs(duration.getSeconds());
        if (!haveDaylightSavings()) {
            return seconds;
        }
        if (judgeSumOrWin(responseTime) && (isInOverLap || !judgeSumOrWin(endTime))) {
            if (!judgeSumOrWin(responseTime.plusHours(1))) {
                LocalDateTime time = responseTime.withHour(1).withMinute(0).withSecond(0);
                LocalDateTime time1 = responseTime.withHour(2).withMinute(0).withSecond(0);
                long seconds1 = Duration.between(responseTime, time1).getSeconds();
                long seconds2 = Duration.between(time, endTime).getSeconds();
                return seconds1 + seconds2;
            } else {
                return seconds + Number.N3600;
            }
        }
        if (!judgeSumOrWin(responseTime) && judgeSumOrWin(endTime)) {
            return seconds - Number.N3600;
        }

        return seconds;
    }

    /**
     * 计算费用
     * @return
     */
    public BigDecimal calculateFee() throws DException {
        long span = calculateTimeSpan();
        long hours = span / Number.N3600;
        long minutes = span / Number.N60;
        long seconds = span - minutes * Number.N60;
        BigDecimal feeTime = BigDecimal.valueOf(minutes + Math.ceil(1.0 * seconds / Number.N60));
        if (hours >= Number.N30) {
            throw new DException("超时");
        } else if (feeTime.intValue() <= Number.N20) {
            return feeTime.multiply(Number.NL20);
        } else {
            return (feeTime.subtract(BigDecimal.valueOf(Number.N20))
                    .multiply(Number.NH20)).add(BigDecimal.valueOf(1));
        }
    }

    /**
     * 判断当前是否处于夏令时
     * @param localDateTime
     * @return
     * true 夏令时
     * false 冬令时
     */
    public boolean judgeSumOrWin(final LocalDateTime localDateTime) {
        ZoneId zoneId = ZoneId.of(zone);
        ZoneRules rules = zoneId.getRules();
        return rules.isDaylightSavings(localDateTime.atZone(zoneId).toInstant());
    }

}
